From 8ba2898e08a8fd1038991d117705990a1fc9e398 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 1 Dec 2016 04:07:20 +0100 Subject: [PATCH] vulkan: acquire/present images when drawing Another step towards the final goal of actually showing something. --- gdk/gdkvulkancontext.c | 159 +++++++++++++++++++++++++++++++--------- gdk/gdkvulkancontext.h | 6 +- gsk/gskvulkanrenderer.c | 27 +++++++ 3 files changed, 157 insertions(+), 35 deletions(-) diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index 03cbbfecd7..f0af29b847 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -36,9 +36,12 @@ struct _GdkVulkanContextPrivate { int swapchain_width, swapchain_height; VkSwapchainKHR swapchain; + VkSemaphore draw_semaphore; guint n_images; VkImage *images; + + uint32_t draw_index; }; enum { @@ -121,13 +124,24 @@ gdk_vulkan_context_dispose (GObject *gobject) GdkVulkanContext *context = GDK_VULKAN_CONTEXT (gobject); GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); GdkDisplay *display; + VkDevice device; g_clear_pointer (&priv->images, g_free); priv->n_images = 0; + device = gdk_vulkan_context_get_device (context); + + if (priv->draw_semaphore != VK_NULL_HANDLE) + { + vkDestroySemaphore (device, + priv->draw_semaphore, + NULL); + priv->draw_semaphore = VK_NULL_HANDLE; + } + if (priv->swapchain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR (gdk_vulkan_context_get_device (context), + vkDestroySwapchainKHR (device, priv->swapchain, NULL); priv->swapchain = VK_NULL_HANDLE; @@ -149,36 +163,6 @@ gdk_vulkan_context_dispose (GObject *gobject) G_OBJECT_CLASS (gdk_vulkan_context_parent_class)->dispose (gobject); } -static void -gdk_vulkan_context_class_init (GdkVulkanContextClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = gdk_vulkan_context_dispose; - - /** - * GdkVulkanContext::images-updated: - * @context: the object on which the signal is emitted - * - * This signal is emitted when the images managed by this context have - * changed. Usually this means that the swapchain had to be recreated, - * for example in response to a change of the window size. - */ - signals[IMAGES_UPDATED] = - g_signal_new (g_intern_static_string ("images-updated"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -gdk_vulkan_context_init (GdkVulkanContext *self) -{ -} - static gboolean gdk_vulkan_context_check_swapchain (GdkVulkanContext *context, GError **error) @@ -259,8 +243,8 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context, if (res == VK_SUCCESS) { - priv->swapchain_width = gdk_window_get_width (window); - priv->swapchain_height = gdk_window_get_height (window); + priv->swapchain_width = capabilities.currentExtent.width; + priv->swapchain_height = capabilities.currentExtent.height; priv->swapchain = new_swapchain; GDK_VK_CHECK (vkGetSwapchainImagesKHR, device, @@ -288,6 +272,84 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context, return res == VK_SUCCESS; } +static void +gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, + cairo_region_t *region) +{ + GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context); + GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + GError *error = NULL; + + if (!gdk_vulkan_context_check_swapchain (context, &error)) + { + g_warning ("%s", error->message); + g_error_free (error); + return; + } + + GDK_VK_CHECK (vkAcquireNextImageKHR, gdk_vulkan_context_get_device (context), + priv->swapchain, + UINT64_MAX, + priv->draw_semaphore, + VK_NULL_HANDLE, + &priv->draw_index); +} + +static void +gdk_vulkan_context_end_frame (GdkDrawContext *draw_context, + cairo_region_t *painted, + cairo_region_t *damage) +{ + GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context); + GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + + GDK_VK_CHECK (vkQueuePresentKHR, gdk_vulkan_context_get_queue (context), + &(VkPresentInfoKHR) { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .swapchainCount = 1, + .pSwapchains = (VkSwapchainKHR[]) { + priv->swapchain + }, + .pImageIndices = (uint32_t[]) { + priv->draw_index + }, + }); +} + +static void +gdk_vulkan_context_class_init (GdkVulkanContextClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass); + + gobject_class->dispose = gdk_vulkan_context_dispose; + + draw_context_class->begin_frame = gdk_vulkan_context_begin_frame; + draw_context_class->end_frame = gdk_vulkan_context_end_frame; + + /** + * GdkVulkanContext::images-updated: + * @context: the object on which the signal is emitted + * + * This signal is emitted when the images managed by this context have + * changed. Usually this means that the swapchain had to be recreated, + * for example in response to a change of the window size. + */ + signals[IMAGES_UPDATED] = + g_signal_new (g_intern_static_string ("images-updated"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +gdk_vulkan_context_init (GdkVulkanContext *self) +{ +} + static gboolean gdk_vulkan_context_real_init (GInitable *initable, GCancellable *cancellable, @@ -350,6 +412,13 @@ gdk_vulkan_context_real_init (GInitable *initable, if (!gdk_vulkan_context_check_swapchain (context, error)) goto out_surface; + GDK_VK_CHECK (vkCreateSemaphore, gdk_vulkan_context_get_device (context), + &(VkSemaphoreCreateInfo) { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + }, + NULL, + &priv->draw_semaphore); + return TRUE; } @@ -417,7 +486,7 @@ gdk_vulkan_context_get_image_format (GdkVulkanContext *context) return priv->image_format.format; } -guint +uint32_t gdk_vulkan_context_get_n_images (GdkVulkanContext *context) { GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); @@ -439,6 +508,28 @@ gdk_vulkan_context_get_image (GdkVulkanContext *context, return priv->images[id]; } +uint32_t +gdk_vulkan_context_get_draw_index (GdkVulkanContext *context) +{ + GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + + g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), 0); + g_return_val_if_fail (gdk_draw_context_is_drawing (GDK_DRAW_CONTEXT (context)), 0); + + return priv->draw_index; +} + +VkSemaphore +gdk_vulkan_context_get_draw_semaphore (GdkVulkanContext *context) +{ + GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context); + + g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), VK_NULL_HANDLE); + g_return_val_if_fail (gdk_draw_context_is_drawing (GDK_DRAW_CONTEXT (context)), VK_NULL_HANDLE); + + return priv->draw_semaphore; +} + static gboolean gdk_display_create_vulkan_device (GdkDisplay *display, GError **error) diff --git a/gdk/gdkvulkancontext.h b/gdk/gdkvulkancontext.h index 2690048e85..1dfa648981 100644 --- a/gdk/gdkvulkancontext.h +++ b/gdk/gdkvulkancontext.h @@ -64,10 +64,14 @@ uint32_t gdk_vulkan_context_get_queue_family_index (GdkVulkanCo GDK_AVAILABLE_IN_3_90 VkFormat gdk_vulkan_context_get_image_format (GdkVulkanContext *context); GDK_AVAILABLE_IN_3_90 -guint gdk_vulkan_context_get_n_images (GdkVulkanContext *context); +uint32_t gdk_vulkan_context_get_n_images (GdkVulkanContext *context); GDK_AVAILABLE_IN_3_90 VkImage gdk_vulkan_context_get_image (GdkVulkanContext *context, guint id); +GDK_AVAILABLE_IN_3_90 +uint32_t gdk_vulkan_context_get_draw_index (GdkVulkanContext *context); +GDK_AVAILABLE_IN_3_90 +VkSemaphore gdk_vulkan_context_get_draw_semaphore (GdkVulkanContext *context); #endif /* GDK_WINDOWING_VULKAN */ diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c index 1bf43297b9..ccae2de02e 100644 --- a/gsk/gskvulkanrenderer.c +++ b/gsk/gskvulkanrenderer.c @@ -285,6 +285,32 @@ gsk_vulkan_renderer_render (GskRenderer *renderer, #endif } +static GdkDrawingContext * +gsk_vulkan_renderer_begin_draw_frame (GskRenderer *renderer, + const cairo_region_t *region) +{ + GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer); + cairo_region_t *whole_window; + GdkDrawingContext *result; + GdkWindow *window; + + window = gsk_renderer_get_window (renderer); + + whole_window = cairo_region_create_rectangle (&(GdkRectangle) { + 0, 0, + gdk_window_get_width (window), + gdk_window_get_height (window) + }); + + result = gdk_window_begin_draw_frame (window, + GDK_DRAW_CONTEXT (self->vulkan), + region); + + cairo_region_destroy (whole_window); + + return result; +} + static void gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass) { @@ -293,6 +319,7 @@ gsk_vulkan_renderer_class_init (GskVulkanRendererClass *klass) renderer_class->realize = gsk_vulkan_renderer_realize; renderer_class->unrealize = gsk_vulkan_renderer_unrealize; renderer_class->render = gsk_vulkan_renderer_render; + renderer_class->begin_draw_frame = gsk_vulkan_renderer_begin_draw_frame; } static void -- 2.30.2